﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright company="Microsoft Corp." file="HpcSchedulerCmdletBase.cs">
//   All rights reserved. See License.txt in the project root for license information.
// </copyright>
// 
// --------------------------------------------------------------------------------------------------------------------
namespace CloudBlitz.Powershell.Cmdlets
{
    using System;
    using System.Management.Automation;
    using System.Net;
    using System.Security.Authentication;
    using System.Threading.Tasks;
    using System.Xml;

    using HpcSchedulerManagement;

    public class HpcSchedulerCmdletBase : PSCmdlet
    {
        protected const string DefaultApiVersion = "2011-11-01";

        protected const string ServiceBaseAddressFormat = "https://{0}.cloudapp.net/WindowsHPC/";

        [Parameter(Mandatory = true)]
        [ValidateNotNull]
        public HpcSchedulerCredentials Credentials { get; set; }

        [Parameter]
        public string ApiVersion { get; set; }

        protected override void ProcessRecord()
        {
            base.ProcessRecord();

            if (string.IsNullOrEmpty(this.Credentials.ClusterName))
            {
                throw new InvalidCredentialException("Cluster name must be specified.");
            }

            if (string.IsNullOrEmpty(this.Credentials.AdminLogin))
            {
                throw new InvalidCredentialException("Admin login must be specified.");
            }

            if (string.IsNullOrEmpty(this.Credentials.AdminPassword))
            {
                throw new InvalidCredentialException("Admin password must be specified.");
            }

            if (string.IsNullOrEmpty(this.Credentials.CertificateThumbprint))
            {
                throw new InvalidCredentialException("SSL certificate thumbprint must be specified.");
            }
        }

        protected HpcSchedulerServiceClient CreateClient()
        {
            var credentials = new HpcSchedulerServiceCredentials(
                                                        this.Credentials.AdminLogin,
                                                        this.Credentials.AdminPassword,
                                                        this.Credentials.CertificateThumbprint);

            var apiVersion = string.IsNullOrEmpty(this.ApiVersion) ? DefaultApiVersion : this.ApiVersion;
            var baseAddress = new Uri(string.Format(ServiceBaseAddressFormat, this.Credentials.ClusterName));

            return new HpcSchedulerServiceClient(new HpcSchedulerServiceContext(credentials, baseAddress, apiVersion));            
        }

        protected async Task<ErrorRecord> HandleException(Exception ex)
        {
            if (ex is AggregateException)
            {
                if (ex.InnerException is WebException)
                {
                    var webException = ex.InnerException as WebException;
                    if (webException.Response == null)
                    {
                        if (webException.InnerException != null)
                        {
                            return this.CreateErrorRecord(webException.InnerException);
                        }

                        return this.CreateErrorRecord(webException);
                    }

                    var settings = new XmlReaderSettings
                    {
                        Async = true,
                        DtdProcessing = DtdProcessing.Ignore
                    };

                    using (var xmlReader = XmlReader.Create((ex.InnerException as WebException).Response.GetResponseStream(), settings))
                    {
                        while (await xmlReader.ReadAsync())
                        {
                            switch (xmlReader.NodeType)
                            {
                                case XmlNodeType.Text:
                                    return new ErrorRecord(ex.InnerException, string.Empty, ErrorCategory.NotSpecified, this)
                                            {
                                                ErrorDetails = new ErrorDetails(await xmlReader.GetValueAsync())
                                            };
                            }
                        }
                    }
                }
                else
                {
                    return this.CreateErrorRecord(ex.InnerException);
                }
            }

            return this.CreateErrorRecord(ex);
        }

        private ErrorRecord CreateErrorRecord(Exception exception)
        {
            return new ErrorRecord(exception, string.Empty, ErrorCategory.NotSpecified, this)
            {
                ErrorDetails = new ErrorDetails(exception.Message)
            };
        }
    }
}